#include "routing/rtp_packet.h"
#include <asm/byteorder.h>

const int CRTPPacket::sRTP_CSRC_FieldLength = 4;
const int CRTPPacket::sRTP_Extension_FieldLength = 4;
const int CRTPPacket::sRTP_Payload_Type_PCMU = 0x00;
const int CRTPPacket::sRTP_Payload_Type_PCMA = 0x08;
const int CRTPPacket::sRTP_Version = 0x02;

struct rtphdr
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
  uint32_t mCSRC_count:4,
           mExtension:1, 
           mPadding:1, 
           mVersion:2, 
           mPayload_type:7, 
           mMarker:1, 
#elif defined(__BIG_ENDIAN_BITFIELD)
  uint32_t mVersion:2, 
           mPadding:1, 
           mExtension:1, 
           mCSRC_count:4, 
           mMarker:1, 
           mPayload_type:7, 
#endif
           mSequence_number:16;
  uint32_t mTimestamp;
  uint32_t mSynchronization_source;
};

CRTPPacket::CRTPPacket(CIPPacket* pIPPacket) : 
	mIPPacket(pIPPacket),
	mRTPHeader(reinterpret_cast<struct rtphdr*>(pIPPacket->getPayload()))
{
	/* fill out headers, payload, etc. */
	/* mRTPHeader = reinterpret_cast<struct rtphdr*>(pIPPacket->getPayload()); */
	mPayload = pIPPacket->getPayload();
	mPayload += sizeof(struct rtphdr) + 
		mRTPHeader->mCSRC_count * sRTP_CSRC_FieldLength +
		mRTPHeader->mExtension * sRTP_Extension_FieldLength;
}

CRTPPacket::~CRTPPacket()
{
}

CRTPPacket* CRTPPacket::createRTPPacket(CIPPacket* pIPPacket)
{
	if(!isRTPPacket(pIPPacket))
	{
		return NULL;
	}

	return new CRTPPacket(pIPPacket);
}

int CRTPPacket::destroyRTPPacket(CRTPPacket* pRTPPacket)
{
	delete pRTPPacket;
	return 0; /* success */
}

bool CRTPPacket::isRTPPacket(CIPPacket* pIPPacket) 
{
	if(pIPPacket->isUDP() == true)
	{
		if(pIPPacket->getSrcPort() >= 1024 &&
				pIPPacket->getDstPort() >= 1024)
		{
			struct rtphdr* lRTPHeader = reinterpret_cast<struct rtphdr*>(pIPPacket->getPayload());
			if(lRTPHeader->mVersion == sRTP_Version &&
					(lRTPHeader->mPayload_type == sRTP_Payload_Type_PCMU ||
					 lRTPHeader->mPayload_type == sRTP_Payload_Type_PCMA))
			{
				return true;
			}
		}
	}
	return false;
}

uint8_t CRTPPacket::getRTPVersion() const
{
	return mRTPHeader->mVersion;
}

NAudioFormats::ECodec CRTPPacket::getPayloadType() const
{
	switch(mRTPHeader->mPayload_type)
	{
		case sRTP_Payload_Type_PCMU:
			return NAudioFormats::ULAW;
			break;
		case sRTP_Payload_Type_PCMA:
			return NAudioFormats::ALAW;
			break;
		default:
			break;
	}
	return NAudioFormats::UNKNOWN_CODEC;
}

uint16_t CRTPPacket::getSequenceNumber() const
{
	return mRTPHeader->mSequence_number;
}

uint8_t* CRTPPacket::getPayload() const
{
	if(!mIPPacket)
	{
		return NULL;
	}

	return mPayload;
}

uint8_t CRTPPacket::getRTPHeaderLength() const
{
	/* subtract address of the UDP/IP payload from the RTP payload */
	return (mPayload - mIPPacket->getPayload());
}

uint32_t CRTPPacket::getPayloadLength() const
{
	return (mIPPacket->getPayloadLength() - getRTPHeaderLength());
}

